package com.lakeworks.listener;

import com.lakeworks.common.constant.HttpStatus;
import com.lakeworks.common.core.domain.AjaxResult;
import com.lakeworks.common.enums.OprProductType;
import com.lakeworks.common.enums.ShipMentType;
import com.lakeworks.common.exception.response.ResponseException;
import com.lakeworks.common.utils.StringUtils;
import com.lakeworks.domain.OprAttachment;
import com.lakeworks.domain.OprProduct;
import com.lakeworks.domain.OprShipment;
import com.lakeworks.domain.SysRobot;
import com.lakeworks.domain.vo.AttachmentVO;
import com.lakeworks.domain.vo.CompanionInfo;
import com.lakeworks.event.*;
import com.lakeworks.service.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Function;

import static java.util.Optional.ofNullable;

@Component
public class RobotListener {

    private static final Logger log = LoggerFactory.getLogger(RobotListener.class);
    @Autowired
    private IOprPickupService oprPickupService;
    @Autowired
    private ISysRobotService sysRobotService;
    @Autowired
    private IOprProductService oprProductService;
    @Autowired
    private IOprShipmentService oprShipmentService;
    @Autowired
    private IOprAttachmentService oprAttachmentService;

    private final Function<String,Boolean> getAutoStatus = code ->{
        AtomicBoolean b = new AtomicBoolean(false);
        ofNullable(sysRobotService.selectAutoByCode(code)).ifPresent(s->{
            if (s.getAuto().equals("0")) {
                b.set(true);
            }
        });
        return b.get();
    };

    /**
     * 监听准备核查事件判断是否自动修改入场单签收状态
     */
    @EventListener
    public void autoPickupSignFor(CheckEvent event) {
        if (getAutoStatus.apply(event.getRobotType().getValue())) {
            log.info(event.getRobotType().getName());
            AjaxResult result = oprPickupService.signFor(event.getExpressNo(), false);
            if (result.get(AjaxResult.CODE_TAG).equals(HttpStatus.ERROR)) {
                throw new ResponseException("签收失败:" + result.get(AjaxResult.MSG_TAG).toString());
            }
        }
    }

    /**
     * 监听进洗涤车间事件判断作业产品是否自动修改洗涤中
     */
    @EventListener
    public void autoProductWashing(WashingEvent event) {
        if (getAutoStatus.apply(event.getRobotType().getValue())) {
            log.info(event.getRobotType().getName());
            AjaxResult result = oprProductService.washing(event.getBarcode(), false);
            if (result.get(AjaxResult.CODE_TAG).equals(HttpStatus.ERROR)) {
                throw new ResponseException("进洗涤车间失败:" + result.get(AjaxResult.MSG_TAG).toString());
            }
        }
    }

    /**
     * 监听出洗涤车间事件判断作业产品是否自动修改已洗涤
     */
    @EventListener
    public void autoProductWashed(WashedEvent event) {
        if (getAutoStatus.apply(event.getRobotType().getValue())) {
            log.info(event.getRobotType().getName());
            AjaxResult result = oprProductService.washed(event.getBarcode(), false);
            if (result.get(AjaxResult.CODE_TAG).equals(HttpStatus.ERROR)) {
                throw new ResponseException("出洗涤车间失败:" + result.get(AjaxResult.MSG_TAG).toString());
            }
        }
    }

    /**
     * 监听后处理事件判断作业产品是否自动修改待质检
     */
    @EventListener
    public void autoProductToinspect(ToinspectEvent event) {
        if (getAutoStatus.apply(event.getRobotType().getValue())) {
            log.info(event.getRobotType().getName());
            AjaxResult result = oprProductService.toinspect(event.getBarcode(), false);
            if (result.get(AjaxResult.CODE_TAG).equals(HttpStatus.ERROR)) {
                throw new ResponseException("修改待质检失败:" + result.get(AjaxResult.MSG_TAG).toString());
            }
        }
    }

    /**
     * 监听后处理事件判断作业产品是否自动修改已上架
     */
    @EventListener
    public void autoProductToPutawat(PutawayEvent event) {
        if (getAutoStatus.apply(event.getRobotType().getValue())) {
            log.info(event.getRobotType().getName());
            AjaxResult result = oprProductService.putaway(event.getBarcode(), false);
            if (result.get(AjaxResult.CODE_TAG).equals(HttpStatus.ERROR)) {
                throw new ResponseException("修改已上架失败:" + result.get(AjaxResult.MSG_TAG).toString());
            }
        }
    }

    /**
     * 监听打包开始事件判断作业产品是否自动修改已拣货
     */
    @EventListener
    public void autoProductTopick(TopickEvent event) {
        if (getAutoStatus.apply(event.getRobotType().getValue())) {
            log.info(event.getRobotType().getName());
            List<OprProduct> products = oprProductService.selectByShipmentId(event.getShipmentId());
            for (OprProduct product : products) {
                AjaxResult result = oprProductService.topick(product.getBarcode(), false);
                if (result.get(AjaxResult.CODE_TAG).equals(HttpStatus.ERROR)) {
                    throw new ResponseException("修改已拣货失败:" + result.get(AjaxResult.MSG_TAG).toString());
                }
            }
        }
    }

    /**
     * 监听打包开始事件判断作业产品是否自动修改已拣货
     */
    @EventListener
    public void autoOutFactory(OutFactoryEvent event) {
        if (getAutoStatus.apply(event.getRobotType().getValue())) {
            log.info(event.getRobotType().getName());
            AjaxResult result = oprProductService.outFactory(event.getExpressNo());
            if (result.get(AjaxResult.CODE_TAG).equals(HttpStatus.ERROR)) {
                throw new ResponseException("出厂失败:" + result.get(AjaxResult.MSG_TAG).toString());
            }
        }
    }

    /**
     * 监听物流单下发成功事件自动获取拣货单
     */
    @EventListener
    public void autoPicking(PickingEvent event){
        if(getAutoStatus.apply(event.getRobotType().getValue())){
            log.info(event.getRobotType().getName());
            List<Long> list = new ArrayList<>();
            list.add(event.getShipmentId());
            AjaxResult result = oprShipmentService.picking(list);
            if (result.get(AjaxResult.CODE_TAG).equals(HttpStatus.ERROR)) {
                throw new ResponseException("获取拣货单失败:" + result.get(AjaxResult.MSG_TAG).toString());
            }
        }
    }




    /**
     * 监听开始包装事件自动质检
     */
    @EventListener
    public void autoQuality(QualityEvent event){
            log.info("触发自动质检配附件");
            log.info(event.getRobotType().getName());
            if (event.getCompanionInfo() != null){
                CompanionInfo companionInfo = event.getCompanionInfo();
                if(!companionInfo.getPrimaryProduct().getStatus().equals(OprProductType.ATTACH.getValue())){
                    AjaxResult result = oprProductService.getProductByBarcode(companionInfo.getPrimaryProduct().getBarcode());
                    if(result.get(AjaxResult.CODE_TAG).equals(HttpStatus.SUCCESS)){
                        AjaxResult qualResult;
                        if(StringUtils.isBlank(companionInfo.getCompanionProduct().getBarcode())){
                            qualResult = oprProductService.qualified(companionInfo.getPrimaryProduct().getBarcode(),null);
                        }else {
                            qualResult = oprProductService.pairQualified(companionInfo.getPrimaryProduct().getBarcode(), companionInfo.getCompanionProduct().getBarcode());
                        }
                        if(!qualResult.get(AjaxResult.CODE_TAG).equals(HttpStatus.SUCCESS)){
                            throw new ResponseException("自动质检失败: "+ result.get(AjaxResult.MSG_TAG).toString());
                        }
                    }else {
                        throw new ResponseException("查询质检详情失败: "+ result.get(AjaxResult.MSG_TAG).toString());
                    }
                }
            }
    }


    /**
     * 监听自动配附件
     */
    @EventListener
    public void autoAttach(AttachEvent event){
        if(getAutoStatus.apply(event.getRobotType().getValue())){
            List<OprAttachment> oprAttachments = oprAttachmentService.selectByProductIdOrCompanionId(event.getProduct().getId());
            if(oprAttachments != null && !oprAttachments.isEmpty()){
                oprAttachments.forEach(a ->{
                    AjaxResult res = oprProductService.attachmentScan(event.getProduct().getBarcode(), a.getBarcode());
                    if(!res.get(AjaxResult.CODE_TAG).equals(HttpStatus.SUCCESS)){
                        throw new ResponseException("附件扫描失败: "+ res.get(AjaxResult.MSG_TAG).toString());
                    }
                });
            }
        }
//        else {
//            if(event.getProduct().getStatus().equals(OprProductType.ATTACH.getValue())){
//                throw new ResponseException("衣物需要去配附件");
//            }
//        }
    }




    /**
     * 监听包装扫描触发自动装箱
     */
    @EventListener
    public void autoPackage(PackageEvent event){
        if(getAutoStatus.apply(event.getRobotType().getValue())){
            log.info(event.getRobotType().getName());
            List<OprProduct> products = oprProductService.selectByShipmentIdExcludeCompanion(event.getShipmentId());
            for (OprProduct product : products) {
                AjaxResult result = oprProductService.packageScan(product.getBarcode());
                if (result.get(AjaxResult.CODE_TAG).equals(HttpStatus.ERROR)) {
                    throw new ResponseException("自动装箱失败:" + result.get(AjaxResult.MSG_TAG).toString());
                }
            }
        }
    }


    @Async
    @EventListener
    public void autoFlow(RecycleEvent event){
        log.info("回收的出厂单自动走完全部流程");
        List<String> barcodeList = event.getBarcodeList();
        barcodeList.forEach(b->{
            OprProduct product = oprProductService.queryByBarcode(b);
            if(product == null){
                throw new ResponseException("回收单走流程失败：水洗码错误");
            }
            if(getProductStatus(product.getId()) <= 5) {
                log.info("回收单走流程：质检");
                oprProductService.getProductByBarcode(b);
                OprProduct pairProduct = oprProductService.queryByCompanionId(product.getId());
                if (pairProduct != null) {
                    oprProductService.pairQualified(b, pairProduct.getBarcode());
                } else {
                    oprProductService.qualified(b, null);
                }
            }
            if(getProductStatus(product.getId()) == 6) {
                log.info("回收单走流程：配附件");
                ofNullable(oprAttachmentService.selectByProductIdOrCompanionId(product.getId())).ifPresent(oprAttachments->oprAttachments.forEach(a->{
                    oprProductService.attachmentScan(product.getBarcode(), a.getBarcode());
                }));
            }
            if(getProductStatus(product.getId()) == 7) {
                log.info("回收单走流程：包装");
                oprProductService.wrap(b);
                //打印总检标
                oprProductService.printCheckLable(b);
            }
        });
        OprShipment shipment = oprShipmentService.selectOprShipmentById(event.getShipmentId());
        if(shipment == null){
            throw new ResponseException("回收单走流程失败：出厂单id错误");
        }
        if (!checkShipmentstatus(shipment.getId())) {
            throw new ResponseException("回收单走流程失败：物流状态错误");
        } else {
            if(getShipmentStatus(shipment.getId()) == 3) {
                log.info("回收单走流程：拣货");
                List<Long> ShipmentIds = new ArrayList<>();
                ShipmentIds.add(shipment.getId());
                oprShipmentService.picking(ShipmentIds);
            }
            if(getShipmentStatus(shipment.getId()) >= 4 && getShipmentStatus(shipment.getId()) <= 7) {
                log.info("回收单走流程：装箱");
                barcodeList.forEach(b->{
                    oprProductService.packageDetail(b);
                    oprProductService.packageScan(b);
                });
            }
            log.info("回收单走流程：出厂");
            oprProductService.outFactory(oprShipmentService.selectOprShipmentById(event.getShipmentId()).getExpressNo());
        }

    }


    private int getProductStatus(Long productId){
        return Integer.parseInt(oprProductService.selectOprProductById(productId).getStatus());
    }

    private int getShipmentStatus(Long shipmentId){
       return Integer.parseInt(oprShipmentService.selectOprShipmentById(shipmentId).getStatus());
    }


    private boolean checkShipmentstatus(Long shipmentId){
        int maxRetries = 10;
        int retries = 0;
        boolean statusMatched = false;
        while (retries < maxRetries && !statusMatched) {
            OprShipment shipment = oprShipmentService.selectOprShipmentById(shipmentId);
            if (StringUtils.isBlank(shipment.getExpressNo())) {
                try {
                    // 等待一秒
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                retries++;
            } else {
                statusMatched = true;
            }
        }
        return statusMatched;

    }

}
